/**
 * 最简单的路径追踪模型
 * 只针对基础模型, 球. 矩形 等做反弹, 无 bvh
 */

import {
  Ray3,
  Vec3,
  add3,
  cross3,
  distance3,
  dot3,
  scale3,
  substract3,
  vec3,
} from '@dlz/toolkit'

class Sphere {
  constructor(
    public center: Vec3,
    public radius: number,
    public color = vec3(0.5, 0.5, 0.5)
  ) {
    //
  }

  intersect(ray: Ray3) {
    const { center, radius } = this
    const { pt, dir } = ray

    const vec = substract3(center, pt)
    const t = dot3(vec, dir)
    scale3(dir, t, vec)
    add3(pt, vec, vec)

    const dis = distance3(vec, center)

    if (dis >= radius) return null
    // if (dis === radius) {
    //   return t >= 0 ? vec : null
    // }

    const halfChoord = Math.sqrt(radius ** 2 - dis ** 2)
    const t1 = t - halfChoord
    const t2 = t + halfChoord

    const ret = vec3()
    if (t2 < 0) {
      // 射线起点在球外部, 但延长线和球有交点
      return null
    } else if (t1 < 0) {
      // 说明射线起点在球内部
      return add3(pt, scale3(dir, t2, ret), ret)
    } else {
      // 存在2个交点
      return add3(pt, scale3(dir, t1, ret), ret)
    }
  }
}

class Rect {
  public center: Vec3
  public normal: Vec3

  constructor(
    public a: Vec3,
    public b: Vec3,
    public c: Vec3,
    public d: Vec3,
    public color = vec3(0.5, 0.5, 0.5)
  ) {
    this.center = {
      x: (a.x + c.x) / 2,
      y: (a.y + c.y) / 2,
      z: (a.z + c.z) / 2,
    }

    const ab = substract3(b, a)
    const ac = substract3(c, a)
    this.normal = cross3(ab, ac)
  }
}

class RectLight extends Rect {
  isLight = true
  intensity = 1

  constructor(a: Vec3, b: Vec3, c: Vec3, d: Vec3, color = vec3(1, 1, 1)) {
    super(a, b, c, d, color)
  }
}

function reflect(v: Vec3, n: Vec3, out = vec3()) {
  const l = dot3(v, n) * 2
  out.x = n.x * l - v.x
  out.y = n.y * l - v.y

  return out
}

interface Opt {
  fov: number
  width: number
  height: number
}

export function simpleTrace(opt: Opt) {
  let { fov, width, height } = opt

  width = Math.ceil(width)
  height = Math.ceil(height)

  const halfWidth = width / 2
  const z = -halfWidth / Math.tan((fov * Math.PI) / 360)

  const meshs = [
    // 底面
    new Rect(
      { x: -100, y: -100, z: -100 },
      { x: -100, y: -100, z: 100 },
      { x: 100, y: -100, z: 100 },
      { x: 100, y: -100, z: -100 }
    ),

    // 背面
    new Rect(
      { x: -100, y: -100, z: -100 },
      { x: 100, y: -100, z: -100 },
      { x: 100, y: 100, z: -100 },
      { x: -100, y: 100, z: -100 }
    ),

    // 顶面
    new Rect(
      { x: -100, y: 100, z: -100 },
      { x: 100, y: 100, z: -100 },
      { x: 100, y: 100, z: 100 },
      { x: -100, y: 100, z: 100 }
    ),

    // 左面
    new Rect(
      { x: -100, y: 100, z: 100 },
      { x: -100, y: -100, z: 100 },
      { x: -100, y: -100, z: -100 },
      { x: -100, y: 100, z: -100 },
      { x: 1, y: 0, z: 0 }
    ),

    // 右面
    new Rect(
      { x: 100, y: 100, z: 100 },
      { x: 100, y: 100, z: -100 },
      { x: 100, y: -100, z: -100 },
      { x: 100, y: -100, z: 100 },
      { x: 0, y: 1, z: 0 }
    ),

    // 顶灯
    new RectLight(
      { x: -50, y: 100, z: -50 },
      { x: 50, y: 100, z: -50 },
      { x: 50, y: 100, z: 50 },
      { x: -50, y: 100, z: 50 }
    ),

    new Sphere({ x: -10, y: 10, z: 0 }, 10),
    new Sphere({ x: 10, y: 10, z: 0 }, 10),
  ]

  for (let j = 0; j < height; j++) {
    for (let i = 0; i < width; i++) {
      const center = {
        x: i + 0.5,
        y: j + 0.5,
        z,
      }
    }
  }

  function trace() {
    //
  }
}
